package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

type CPU struct {
	code     []byte
	memory   [30000]int
	filename string
	char     []byte
	counter  int
}

func (self *CPU) New(filename string) {

	self.filename = filename
	self.char = make([]byte, 1)
	self.counter = 0

	self.ReadFile()
	self.Exec()

}
func (self *CPU) ReadFile() {

	code, err := ioutil.ReadFile(self.filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(-1)
	}
	self.code = code

}

func (self *CPU) Input() error {
	var input io.Reader
	input = os.Stdin

	_, err := input.Read(self.char)
	self.memory[self.counter] = int(self.char[0])

	return err
}

func (self *CPU) Print() error {
	self.char[0] = byte(self.memory[self.counter])

	var output io.Writer
	output = os.Stdout
	_, err := output.Write(self.char)
	return err
}
func (self CPU) Exec() {

	var i int

	for i < len(self.code) {

		ins := self.code[i]

		switch ins {

		case '+':
			self.memory[self.counter]++

		case '-':
			self.memory[self.counter]--
		case '>':
			self.counter = self.counter + 1
		case '<':

			self.counter = self.counter - 1
		case '.':
			err := self.Print()
			if err != nil {
				panic(err)
			}
		case ',':
			err := self.Input()
			if err != nil {
				panic(err)
			}
		case '[':
			if self.memory[self.counter] == 0 {
				depth := 1
				for depth != 0 {
					i++
					switch self.code[i] {
					case '[':
						depth++
					case ']':
						depth--
					}
				}

			}
		case ']':
			if self.memory[self.counter] != 0 {
				depth := 1
				for depth != 0 {
					i--
					switch self.code[i] {
					case ']':
						depth++
					case '[':
						depth--
					}
				}
			}
		}
		i++
	}
}
func main() {
	var filename string
env := os.Args
if(len(env) == 1) {
fmt.Println("no filename")
return
} else {
filename = env[1]
}
	cpu := CPU{}
	cpu.New(filename)

}
